﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Bluyel.Core
{
    /// <summary>
    /// Physical Quantity data converter.
    /// from a prefix to another one.
    /// 
    /// Provide also comparisons methods.
    /// </summary>
    public class PhyConverter
    {
        TypeMgrBase _typeMgr;

        TypeFinderBase _typeFinder;

        ValueBuilder _valueBuilder;

        //=====================================================================
        #region Constructor.

        //---------------------------------------------------------------------
        /// <summary>
        /// Constructor.
        /// </summary>
        public PhyConverter(TypeMgrBase typeMgr, TypeFinderBase typeFinder, ValueBuilder valueBuilder)
        {
            _typeMgr = typeMgr;
            _typeFinder= typeFinder;
            _valueBuilder = valueBuilder;
        }
        #endregion

        //=====================================================================
        #region Public Length conversion methods.

        //---------------------------------------------------------------------
        /// <summary>
        /// Convert a length, to another tager prefix.
        /// Create a new Data value.
        /// 
        /// </summary>
        /// <param name="dvLength"></param>
        /// <param name="targetPrefix"></param>
        /// <returns></returns>
        public ValuePhyLength ConvertTo(ValuePhyLength dvLength, TypePhyLengthPrefix targetPrefix)
        {
            if (dvLength == null)
                return null;

            // source prefix and target prefix are equals, no need to convert
            if (dvLength.Prefix == targetPrefix)
                // create a new dvLength
                return _valueBuilder.CreateValuePhyLength(dvLength.Value, targetPrefix);            

            // get the value coefficient of the prefix
            double valCoeff = _typeMgr.GetValCoeff(dvLength.Prefix, targetPrefix);

            // calculate the new val of the length
            double newVal= dvLength.Value * valCoeff;

            // create a new dvLength
            return  _valueBuilder.CreateValuePhyLength(newVal, targetPrefix);            
        }

        // ChangePrefix(): update the prefix, so update the inner value

        #endregion

        //---------------------------------------------------------------------
        /// <summary>
        /// Return true if A > B.
        /// </summary>
        /// <param name="dvLengthA"></param>
        /// <param name="dvLengthB"></param>
        /// <returns></returns>
        public bool IsGreaterThan(ValuePhyLength dvLengthA, ValuePhyLength dvLengthB)
        {
            if (dvLengthA == null)
                return false;
            if (dvLengthB == null)
                return false;

            // need to use the same reference: the metre for both lengths dv
            ValuePhyLength dvLengthAm = ConvertTo(dvLengthA, TypePhyLengthPrefix.Metre);
            ValuePhyLength dvLengthBm = ConvertTo(dvLengthB, TypePhyLengthPrefix.Metre);

            // compare
            return (dvLengthAm.Value > dvLengthBm.Value);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Return true if A < B.
        /// </summary>
        /// <param name="dvLengthA"></param>
        /// <param name="dvLengthB"></param>
        /// <returns></returns>
        public bool IsLessThan(ValuePhyLength dvLengthA, ValuePhyLength dvLengthB)
        {
            if (dvLengthA == null)
                return false;
            if (dvLengthB == null)
                return false;

            // need to use the same reference: the metre for both lengths dv
            ValuePhyLength dvLengthAm = ConvertTo(dvLengthA, TypePhyLengthPrefix.Metre);
            ValuePhyLength dvLengthBm = ConvertTo(dvLengthB, TypePhyLengthPrefix.Metre);

            // compare
            return (dvLengthAm.Value < dvLengthBm.Value);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Return true if A >= B.
        /// </summary>
        /// <param name="dvLengthA"></param>
        /// <param name="dvLengthB"></param>
        /// <returns></returns>
        public bool IsGreaterEqualsThan(ValuePhyLength dvLengthA, ValuePhyLength dvLengthB)
        {
            if (dvLengthA == null)
                return false;
            if (dvLengthB == null)
                return false;

            // need to use the same reference: the metre for both lengths dv
            ValuePhyLength dvLengthAm = ConvertTo(dvLengthA, TypePhyLengthPrefix.Metre);
            ValuePhyLength dvLengthBm = ConvertTo(dvLengthB, TypePhyLengthPrefix.Metre);

            // compare
            return (dvLengthAm.Value >= dvLengthBm.Value);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Return true if A =< B.
        /// </summary>
        /// <param name="dvLengthA"></param>
        /// <param name="dvLengthB"></param>
        /// <returns></returns>
        public bool IsLessEqualsThan(ValuePhyLength dvLengthA, ValuePhyLength dvLengthB)
        {
            if (dvLengthA == null)
                return false;
            if (dvLengthB == null)
                return false;

            // need to use the same reference: the metre for both lengths dv
            ValuePhyLength dvLengthAm = ConvertTo(dvLengthA, TypePhyLengthPrefix.Metre);
            ValuePhyLength dvLengthBm = ConvertTo(dvLengthB, TypePhyLengthPrefix.Metre);

            // compare
            return (dvLengthAm.Value <= dvLengthBm.Value);
        }

        //---------------------------------------------------------------------
        /// <summary>
        /// Return true if A == B.
        /// </summary>
        /// <param name="dvLengthA"></param>
        /// <param name="dvLengthB"></param>
        /// <returns></returns>
        public bool AreEquals(ValuePhyLength dvLengthA, ValuePhyLength dvLengthB)
        {
            if (dvLengthA == null)
                return false;
            if (dvLengthB == null)
                return false;

            // need to use the same reference: the metre for both lengths dv
            ValuePhyLength dvLengthAm = ConvertTo(dvLengthA, TypePhyLengthPrefix.Metre);
            ValuePhyLength dvLengthBm = ConvertTo(dvLengthB, TypePhyLengthPrefix.Metre);

            // compare
            return (dvLengthAm.Value == dvLengthBm.Value);
        }

    }
}
